/*
*	Copyright (C) 2014  Julio Montes, Mario Carrillo
*	
*	Julio Montes e-mail: imc.coder@gmail.com 
*
*	Mario Carrillo e-mail: mario_90ago@live.com.mx
*
*	BSD 3-Clause License
*/

#include "alliance/include/toolpanel.h"
#include "alliance/include/argumentctrl.h"
#include "alliance/include/optionctrl.h"
#include "alliance/include/envarpanel.h"
#include "alliance/include/toolctrl.h"
#include "alliance/include/tool.h"
#include "alliance/include/path.h"
#include "alliance/include/buildoptionsdlg.h"

#include "sdk/include/util.h"

#include <wx/tokenzr.h>

namespace alliance
{
    const wxString ToolPanel::s_fileExtensionTool = _T( "tool" );

    ToolPanel::ToolPanel( wxWindow *parent, wxWindowID id )
        : wxPanel( parent, id )
        , m_command( wxEmptyString )
        , m_boxSizer( NULL )
        , m_envarPanel( NULL )
    {

    }

    ToolPanel::~ToolPanel()
    {

    }

    void ToolPanel::AddFilesToArray( wxArrayString *arrayFiles ) const
    {
        std::map<wxString,ToolCtrl *>::const_iterator it;
        const std::map<wxString,ToolCtrl *>::const_iterator &it_end = m_controls.end();
        for( it=m_controls.begin(); it != it_end; ++it )
        {
            ArgumentCtrl *argctrl = dynamic_cast<ArgumentCtrl *>( it->second );
            if( argctrl != NULL && argctrl->IsAddedToGeneratedFiles() && !argctrl->GetText().IsEmpty() )
            {
                const wxString &text = argctrl->GetText();
                if( wxNOT_FOUND == arrayFiles->Index( text ) &&
                    wxNOT_FOUND == BuildOptionsDialog::s_arrayDirectoryFiles.Index( text ) &&
                    wxNOT_FOUND == BuildOptionsDialog::s_arrayProjectFiles.Index( text ) )
                {
                    arrayFiles->Add( text );
                }
            }
        }
    }

    bool ToolPanel::IsOk() const
    {
        std::map<wxString,ToolCtrl *>::const_iterator it;
        const std::map<wxString,ToolCtrl *>::const_iterator &it_end = m_controls.end();
        for( it=m_controls.begin(); it != it_end; ++it )
        {
            if( !it->second->IsOk() )
            {
                return false;
            }
        }

        return true;
    }

    Tool ToolPanel::GetTool() const
    {
        Tool tool( m_command, m_commandFormat );
        std::map<wxString,ToolCtrl *>::const_iterator it;
        const std::map<wxString,ToolCtrl *>::const_iterator &it_end = m_controls.end();
        for( it=m_controls.begin(); it != it_end; ++it )
        {
            ArgumentCtrl *argctrl = dynamic_cast<ArgumentCtrl *>( it->second );
            if( argctrl != NULL )
            {
                if( argctrl->HasInputField() )
                {
                    tool.AddOther( argctrl->GetKey(), argctrl->GetText(), argctrl->GetType() );
                }
            }
            else
            {
                OptionCtrl *optctrl = dynamic_cast<OptionCtrl *>( it->second );
                if( optctrl->IsChecked() )
                {
                    tool.AddOption( optctrl->GetKey(), optctrl->GetText() );
                }
            }
        }

        if( m_envarPanel != NULL )
        {
            VectorVariables variables;
            m_envarPanel->GetVariables( &variables );
            for( size_t i=0; i<variables.size(); ++i )
            {
                tool.AddVariable( variables[i].name, variables[i].value );
            }
        }

        return tool;
    }

    bool ToolPanel::LoadTool( const Tool &tool )
    {
        wxString toolFile = Path::s_dirTools + tool.GetName() + _T( "." ) + s_fileExtensionTool;
        if( !wxFileExists( toolFile ) )
        {
            //TODO: show error
            return false;
        }

        if( !LoadFile( toolFile ) )
        {
            return false;
        }

        //set inputs and others
        const vectorOthers &vOthers = tool.GetOthers();
        for( size_t i=0; i<vOthers.size(); ++i )
        {
            const sdk::vectorAttributesString &vAttributes = vOthers[i].vectorAttributes;
            for( size_t j=0; j<vAttributes.size(); ++j )
            {
                const wxString &name=vAttributes[j].name;
                if( 0 == name.Cmp( _T( "value" ) ) )
                {
                    SetValue( vOthers[i].name, vAttributes[j].value );
                }
            }
        }

        //set option
        const vectorOptions &vOption = tool.GetOptions();
        for( size_t i=0; i<vOption.size(); ++i )
        {
            const sdk::vectorAttributesString &vAttributes = vOption[i].vectorAttributes;
            bool hasAdditional = false;
            wxString option;
            wxString additional;
            for( size_t j=0; j<vAttributes.size(); ++j )
            {
                if( _T( "value" ) == vAttributes[j].name )
                {
                    option = vAttributes[j].value;
                    SetValue( option, true );
                }
                else if( _T( "additional" ) == vAttributes[j].name )
                {
                    hasAdditional =  true;
                    additional = vAttributes[j].value;
                }
            }

            if( hasAdditional && !option.IsEmpty() )
            {
                SetValue( option, additional );
            }
        }

        if( m_envarPanel != NULL )
        {
            const vectorVariables &vVariables = tool.GetVariables();
            wxString name;
            wxString value;
            for( size_t i=0; i<vVariables.size(); ++i )
            {
                const sdk::vectorAttributesString &vAttributes = vVariables[i].vectorAttributes;
                for( size_t j=0; j<vAttributes.size(); ++j )
                {
                    if( vAttributes[j].name == _T( "name" ) )
                    {
                        name = vAttributes[j].value;
                    }
                    else if( vAttributes[j].name == _T( "value" ) )
                    {
                        value = vAttributes[j].value;
                    }
                }
                m_envarPanel->AddVariable( name, value );
            }
        }

        return true;
    }

    bool ToolPanel::LoadFile( const wxString &filename )
    {
        m_boxSizer = new wxBoxSizer( wxVERTICAL );
        sdk::FileConfig l_toolFile;
        if( !l_toolFile.LoadFile( filename ) )
            return false;

        m_command = l_toolFile.ReadStringAttribute( wxT( "/tool" ), wxT( "command" ) );
        if( m_command.Trim().IsEmpty() )
        {
            //TODO: show error
            return false;
        }

        m_commandFormat = l_toolFile.ReadStringAttribute( wxT( "/tool/command" ), wxT( "value" ) );
        if( m_commandFormat.Trim().IsEmpty() )
        {
            //TODO: show error
            return false;
        }

        sdk::vectorElementsString l_vectorElements;
        l_toolFile.ReadChildren( wxT( "/tool" ), &l_vectorElements );
        size_t l_rowCount = 1;
        size_t l_loadedptions = false;
        for( size_t i=0; i<l_vectorElements.size(); ++i )
        {
            m_boxSizer->AddSpacer( 10 );

            if( 0 == l_vectorElements[i].name.Cmp( wxT( "row" ) ) )
            {
                sdk::vectorElementsString l_vectorElementsRow;
                l_toolFile.ReadChildren( wxT( "/tool/row" ), &l_vectorElementsRow, l_rowCount );
                if( !LoadArguments( l_vectorElementsRow ) )
                {
                    return false;
                }
                ++l_rowCount;
            }
            else if( 0 == l_vectorElements[i].name.Cmp( wxT( "options" ) ) && !l_loadedptions )
            {
                sdk::vectorElementsString l_vectorElementsOptions;
                l_toolFile.ReadChildren( wxT( "/tool/options" ), &l_vectorElementsOptions );
                if( !LoadOptions( l_vectorElementsOptions ) )
                {
                    return false;
                }
                UpdateOptionsDependents();
                l_loadedptions = true;
            }
        }

        m_boxSizer->AddSpacer( 10 );

        if( l_toolFile.ReadBoolAttribute( wxT( "/tool" ), wxT( "envar" ) ) )
        {
            m_envarPanel = new EnvarPanel( this, wxID_ANY );
            m_boxSizer->Add( m_envarPanel, 0, wxEXPAND | wxLEFT | wxRIGHT, 10 );
        }

        SetSizer( m_boxSizer );

        return true;
    }

    void ToolPanel::SetValue( const wxString &key, const wxString &text )
    {
        std::map<wxString,ToolCtrl *>::iterator l_it = m_controls.find( key );
        if( l_it != m_controls.end() )
        {
            l_it->second->SetText( text );
        }
        else
        {
            LOGD( wxT( "Control not found: " ) + key );
        }
    }

    void ToolPanel::SetValue( const wxString &key, bool value )
    {
        std::map<wxString,ToolCtrl *>::iterator l_it = m_controls.find( key );
        if( l_it != m_controls.end() )
        {
            OptionCtrl *l_opt = dynamic_cast<OptionCtrl *>( l_it->second );
            if( l_opt )
            {
                l_opt->Checked( value );
            }
        }
        else
        {
            LOGD( wxT( "Control not found: " ) + key );
        }
    }

    void ToolPanel::AddVariable( const wxString &name, const wxString &value )
    {
        if( m_envarPanel != NULL )
        {
            m_envarPanel->AddVariable( name, value );
        }
    }

    bool ToolPanel::LoadArguments( const sdk::vectorElementsString &vectorElements )
    {
        wxBoxSizer *l_boxSizer = new wxBoxSizer( wxHORIZONTAL );

        for( size_t i=0; i<vectorElements.size(); ++i )
        {
            ArgumentCtrl *l_argCtrl = new ArgumentCtrl( this, wxID_ANY );
            if( !l_argCtrl->Load( vectorElements[i].name, vectorElements[i].vectorAttributes ) )
            {
                return false;
            }

            m_controls[l_argCtrl->GetKey()] = l_argCtrl;

            l_boxSizer->Add( l_argCtrl, 1 );
            l_boxSizer->AddSpacer( 5 );
        }

        m_boxSizer->Add( l_boxSizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 10 );

        return true;
    }

    bool ToolPanel::LoadOptions( const sdk::vectorElementsString &vectorElements )
    {
        wxScrolledWindow *l_scrolledWindow = new wxScrolledWindow( this );
        wxStaticBoxSizer *l_stBoxSizer = new wxStaticBoxSizer( wxVERTICAL, this, wxT( " Options " ) );
        wxBoxSizer *l_boxSizer = new wxBoxSizer( wxVERTICAL );
        m_boxSizer->AddSpacer( 5 );
        for( size_t i=0; i<vectorElements.size(); ++i )
        {
            l_boxSizer->AddSpacer( 5 );

            OptionCtrl *l_optionCtrl = new OptionCtrl( l_scrolledWindow, wxID_ANY );
            if( !l_optionCtrl->Load( vectorElements[i].vectorAttributes ) )
            {
                return false;
            }

            m_controls[l_optionCtrl->GetKey()] = l_optionCtrl;

            l_boxSizer->Add( l_optionCtrl, 0, wxEXPAND );
        }
        l_scrolledWindow->SetSizer( l_boxSizer );
        l_scrolledWindow->FitInside();
        l_scrolledWindow->SetScrollRate( 5, 5 );
        l_stBoxSizer->Add( l_scrolledWindow, 1, wxEXPAND );
        m_boxSizer->Add( l_stBoxSizer, 1, wxEXPAND | wxLEFT | wxRIGHT, 15 );

        return true;
    }

    void ToolPanel::UpdateOptionsDependents()
    {
        std::map<wxString,ToolCtrl *>::iterator it;
        const std::map<wxString,ToolCtrl *>::iterator &it_end = m_controls.end();
        for( it=m_controls.begin(); it != it_end; ++it )
        {
            OptionCtrl *tempCtrl = dynamic_cast<OptionCtrl *>( it->second );
            if( tempCtrl )
            {
                wxStringTokenizer st( tempCtrl->GetDependencies(), wxT( "," ), wxTOKEN_STRTOK );
                while( st.HasMoreTokens() )
                {
                    const wxString l_key = st.GetNextToken();
                    const std::map<wxString,ToolCtrl *>::iterator &l_tempIt = m_controls.find( l_key );
                    if( l_tempIt != m_controls.end() )
                    {
                        OptionCtrl *l_dependencyCtrl = dynamic_cast<OptionCtrl *>( l_tempIt->second );
                        if( l_tempIt != it_end && l_dependencyCtrl )
                        {
                            tempCtrl->AddDependency( l_dependencyCtrl );
                        }
                    }
                    else
                    {
                        LOGD( _T( "option: " ) + l_key + _T( " not exists, required by: " ) + tempCtrl->GetKey() );
                    }
                }

                tempCtrl->CheckDependencies();
            }
        }
    }

    bool ToolPanel::OnPageChanging() const
    {
        std::map<wxString,ToolCtrl *>::const_iterator it;
        for( it = m_controls.begin(); it != m_controls.end(); ++it )
        {
            if( !it->second->IsOk() )
            {
                return false;
            }
        }

        return true;
    }

    bool ToolPanel::OnPageChanged( const wxArrayString &arrayFiles ) const
    {
        std::map<wxString,ToolCtrl *>::const_iterator it;
        for( it = m_controls.begin(); it != m_controls.end(); ++it )
        {
            ArgumentCtrl *argctrl = dynamic_cast<ArgumentCtrl *>( it->second );
            if( argctrl != NULL )
            {
                argctrl->ClearFiles();
                if( argctrl->HasGeneratedFiles() )
                {
                    argctrl->AddFiles( arrayFiles );
                }
                if( argctrl->HasDirFiles() )
                {
                    argctrl->AddFiles( BuildOptionsDialog::s_arrayDirectoryFiles );
                }
                if( argctrl->HasProjectFiles() )
                {
                    argctrl->AddFiles( BuildOptionsDialog::s_arrayProjectFiles );
                }
            }
        }

        return true;
    }
}



